package org.hxzon.demo.jt.logsearcher.util;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.queryparser.flexible.standard.StandardQueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.search.highlight.Highlighter;
import org.apache.lucene.search.highlight.QueryScorer;
import org.apache.lucene.search.highlight.TextFragment;
import org.apache.lucene.search.highlight.TokenSources;
import org.apache.lucene.store.FSDirectory;
import org.hxzon.util.DateFormatUtil;

public class LogFileSearcher {
    private final File baseDir;
    private final String analyzerName;

    //-------------
    //baseDir     索引的根目录，该对象检索的索引均在该目录内
    public LogFileSearcher(String baseDir, String analyzerName) {
        this.baseDir = new File(baseDir);
        this.analyzerName = analyzerName;
    }

    //单目标检索内容
    //indexName   索引名称
    //text        检索内容（也可以为符合检索语法的语句）
    //top         返回的最大记录数
    //返回检索结果列表，列表中的每个记录重组为一行
    public List<String> search(String indexName, String searchText, int top) {
        String indexPath = baseDir.getAbsolutePath() + "/" + indexName;
        List<String> result = new ArrayList<String>();
        IndexReader reader = null;
        try {
            reader = DirectoryReader.open(FSDirectory.open(new File(indexPath)));
            IndexSearcher searcher = new IndexSearcher(reader);
            Analyzer analyzer = LogSearcherConfig.getAnalyzer(analyzerName);
            //QueryParser queryParser = new QueryParser(LogSearcherConfig.LuceneVersion, LogSearcherConfig.FieldName_Content, analyzer);
            StandardQueryParser queryParser = new StandardQueryParser();
            queryParser.setAllowLeadingWildcard(true);
            //queryParser.setAnalyzer(new WhitespaceAnalyzer(LogSearcherConfig.LuceneVersion));
            queryParser.setAnalyzer(analyzer);
            //
            Query query = queryParser.parse(searchText.trim(), LogSearcherConfig.FieldName_Content);
            TopDocs searchResults = searcher.search(query, top);
            ScoreDoc[] hits = searchResults.scoreDocs;
            //for highlighter
            MyHighlighterFormatter htmlFormatter = new MyHighlighterFormatter("<span class=\"hl\">", "</span>");
            Highlighter highlighter = new Highlighter(htmlFormatter, new QueryScorer(query));
            //end for highlighter
            for (int i = 0; i < hits.length; i++) {
                int docId = hits[i].doc;
                Document doc = searcher.doc(docId);
                //logTime
                String logTime = doc.get(LogSearcherConfig.FieldName_LogTime);
                //lineContent
                String lineContent = doc.get(LogSearcherConfig.FieldName_Content);
                //for highlighter
                StringBuilder sb = new StringBuilder("[").append(logTime).append("] ");
                TokenStream tokenStream = TokenSources.getAnyTokenStream(searcher.getIndexReader(), docId, LogSearcherConfig.FieldName_Content, analyzer);
                TextFragment[] frag = highlighter.getBestTextFragments(tokenStream, lineContent, false, 10);
                //highlighter.getBestFragments(tokenStream, lineContent, 3, "...");
                for (int j = 0; j < frag.length; j++) {
                    //if ((frag[j] != null) && (frag[j].getScore() > 0)) {
                    if ((frag[j] != null)) {
                        sb.append(frag[j].toString());
                    }
                }
                result.add(sb.toString());
                //end for highlighter
                //result.add("[" + logTime + "] " + lineContent);
            }

        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                }
            }
        }
        Collections.sort(result, LogComparator.instance);
        return result;
    }

    //多目标检索内容
    //indexNames  索引名称列表
    //text        检索内容（也可以为符合检索语法的语句）
    //top         返回的最大记录数
    //返回检索结果列表，列表中的每个记录重组为一行
    public List<LogList> search(String[] indexNames, String searchText, int top) {
        List<LogList> result = new ArrayList<LogList>();
        for (String indexName : indexNames) {
            LogList logList = new LogList(indexName);
            logList.addAll(search(indexName, searchText, top));
            result.add(logList);
        }
        return result;
    }

    public List<String> listIndexNames() {
        List<String> result = new ArrayList<String>();
        for (File file : this.baseDir.listFiles()) {
            if (file.isDirectory()) {
                result.add(file.getName());
            }
        }
        return result;
    }

    //----------------

    private static void print(String msg) {
        System.out.println(msg);
    }

    private static void print(LogList logList) {
        print("-------------");
        print(logList.getIndexName());
        for (String log : logList) {
            print(log);
        }
    }

    public static void main(String[] args) throws IOException {
        String ana = "smartcn";
        System.out.println(DateFormatUtil.formatToUniteTime());
        String baseDir = LogSearcherConfig.IndexFileBaseDir;
        String[] indexNames = new String[] { "res-" + ana + "-1" };
        String searchText = "马棚";//"(\"粮草\" AND \"马棚\")";
        int top = 300;
        LogFileSearcher searcher = new LogFileSearcher(baseDir, ana);
        List<LogList> results = searcher.search(indexNames, searchText, top);
        System.out.println(DateFormatUtil.formatToUniteTime());
        for (LogList result : results) {
            print(result);
        }
    }

}
